package dbms.ypr;

import dbms.ypr.user.TablePermissions;
import dbms.ypr.user.User;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


public class Select {


    public static void selectSql(String sql) {
        String path = dbms.ypr.SQLConstant.getNowPath();

        String tableName = null;
        if(dbms.ypr.SQLConstant.currentDatabase == null){
            System.out.println("ERROR: 未选定数据库");
        }
        // 判断执行视图
        Pattern compile = Pattern.compile("^select\\s+(\\w+);$", Pattern.CASE_INSENSITIVE);
        Matcher matcher = compile.matcher(sql);
        User loginUser = User.getLoginUser(dbms.ypr.SQLConstant.currentUsername);
        List<String> collect = null;
        if (loginUser.getTablePermissions() != null){
            collect = loginUser.getTablePermissions().stream().map(TablePermissions::getTableName).collect(Collectors.toList());
        } else {
            collect = new ArrayList<>();
        }
        if (matcher.find()) {
            String fileName = matcher.group(1);
            String nowPath = path + "\\" + fileName + ".txt";
            if (!new File(nowPath).exists() && !collect.contains(fileName)) {
                System.out.println("ERROR: 视图" + fileName + "不存在");
                Input.get();
            }
            selectSql(getSelectViewSql(nowPath));
        }

        try {
            List<List<List<Map<String, String>>>> allTables = dbms.ypr.Utils.parseSqlRefTables(sql).stream()
                    .map(tName -> getTableList(tName))
                    .collect(Collectors.toList());
            Pattern compile1 = Pattern.compile("on\\s+(.*)\\s*((where)|;)");
            Matcher matcher1 = compile1.matcher(sql);
            if (matcher1.find()) {
                String group = matcher1.group(1);
                String[] split = group.trim().split("=");
                String key1 = split[0].trim();
                String key2 = split[1].trim();
                if (key1.contains("."))
                    key1 = key1.split("\\.")[1];
                if (key2.contains("."))
                    key2 = key2.split("\\.")[1];
                List<List<Map<String, String>>> table1 = allTables.get(0);
                List<List<Map<String, String>>> table2 = allTables.get(1);
                List<List<Map<String, String>>> resultTable = new ArrayList<>();
                String finalKey1 = key1;
                String finalKey2 = key2;
                table1.forEach(t1 -> {
                    String value1 = t1.stream()
                            .filter(tc -> tc.get("key").equals(finalKey1))
                            .map(a->a.get("value"))
                            .findAny().orElse(null);
                    table2.forEach(t2->{
                        String value2 = t2.stream()
                                .filter(tc -> tc.get("key").equals(finalKey2))
                                .map(a->a.get("value"))
                                .findAny().orElse(null);
                        if (value1.equals(value2)){
                            ArrayList<Map<String, String>> temp = new ArrayList<>();
                            temp.addAll(t1);
                            temp.addAll(t2);
                            resultTable.add(temp);
                        }
                    });
                });
                Map<String, String> whereClause = getWhereClause(sql);
                List<String> tableColumnNames = getTableColumnNames(sql);
                List<List<String>> keys = resultTable.stream().map(a -> {
                    return a.stream().map(b -> b.get("key")).collect(Collectors.toList());
                }).collect(Collectors.toList());
                List<List<String>> list = resultTable.stream()
                        .filter(a->{
                            if (whereClause.size() == 0) return true;
                            for (String key : whereClause.keySet()) {
                                String val = whereClause.get(key);
                                if (a.stream().anyMatch(aa -> key.equals(aa.get("key")) && val.equals(aa.get("value")))){
                                    return true;
                                }
                            }
                            return false;
                        })
                        .map(a -> {
                            return a.stream()
                                    .filter(b->tableColumnNames.contains("*") || tableColumnNames.contains(b.get("key")))
                                    .map(b -> b.get("value")).collect(Collectors.toList());
                        }).collect(Collectors.toList());
                List<String> tarColNames = keys.get(0).stream()
                        .filter(a -> tableColumnNames.contains("*") || tableColumnNames.contains(a))
                        .collect(Collectors.toList());
                System.out.println(TableGenerator.generateTable(tarColNames, list));
            } else {
                Map<String, String> whereClause = getWhereClause(sql);
                List<String> tableColumnNames = getTableColumnNames(sql);
                List<List<Map<String, String>>> lists = allTables.get(0);
                List<List<String>> keys = lists.stream().map(a -> {
                    return a.stream().map(b -> b.get("key")).collect(Collectors.toList());
                }).collect(Collectors.toList());
                List<List<String>> list = lists.stream()
                        .filter(a->{
                            if (whereClause.size() == 0) return true;
                            for (String key : whereClause.keySet()) {
                                String val = whereClause.get(key);
                                if (a.stream().anyMatch(aa -> key.equals(aa.get("key")) && val.equals(aa.get("value")))){
                                    return true;
                                }
                            }
                            return false;
                        })
                        .map(a -> {
                    return a.stream()
                            .filter(b->tableColumnNames.contains("*") || tableColumnNames.contains(b.get("key")))
                            .map(b -> b.get("value")).collect(Collectors.toList());
                }).collect(Collectors.toList());
                List<String> tarColNames = keys.get(0).stream()
                        .filter(a -> tableColumnNames.contains("*") || tableColumnNames.contains(a))
                        .collect(Collectors.toList());
                System.out.println(TableGenerator.generateTable(tarColNames, list));
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("ERROR:解析表名失败");
        }

//        System.out.println(TableGenerator.generateTable(targetColumnName, lists));
        System.out.println("Query OK");

        Input.get();
    }

    //读出数据库中表中第3行中的数据,因为前三行存放的是表的控制信息,三行之后存放的是表的控制信息
    private static List<String> getTableDescribe(String path){

        List<String> list = new ArrayList<>();

        try {
            File file = new File(path);
            FileReader reader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(reader);
            String s = "";
            int index = 1;
            while((s = bufferedReader.readLine()) != null){
                index++;
                if(index > 4){
                    list.add(s);
                }
            }
            bufferedReader.close();
        }catch(IOException e){
            e.printStackTrace();
        }

        return list;
    }

    // 解析表对象
    private static List<List<Map<String, String>>> getTableDataList(List<String> columnName, List<String> types, List<String> dataList){
        List<List<Map<String, String>>> resultList = new ArrayList<>();
        if (columnName.size() == types.size()) {
            dataList.forEach(item-> {
                ArrayList<Map<String, String>> itemList = new ArrayList<>();
                for (int i = 0; i < columnName.size(); i++) {
                    HashMap<String, String> map = new HashMap<>();
                    map.put("key", columnName.get(i));
                    map.put("type", types.get(i));
                    map.put("value", item.split(SQLConstant.getSeparate())[i]);
                    itemList.add(map);
                }
                resultList.add(itemList);
            });
        }
        return resultList;
    }

    private static List<List<Map<String, String>>> getTableList(String tableName){
        String path = SQLConstant.getNowPath();
        String nowPath = path + "\\" + tableName + ".txt";
        User loginUser = User.getLoginUser(SQLConstant.currentUsername);
        List<String> collect = null;
        if (loginUser.getTablePermissions() != null){
            collect = loginUser.getTablePermissions().stream().map(TablePermissions::getTableName).collect(Collectors.toList());
        } else {
            collect = new ArrayList<>();
        }
        if (!new File(nowPath).exists() && !collect.contains(tableName)) {
            System.out.println("ERROR: 表名\'"
                    + (null == SQLConstant.currentDatabase ? "" : SQLConstant.currentDatabase + ".")
                    + tableName + "\'不存在");
            Input.get();
        }
        List<String> columnName = Insert.getColumnName(nowPath, 1);     //获得列名
        List<String> types = Insert.getColumnName(nowPath, 2);     //获得列名
        List<String> list = getTableDescribe(nowPath);
        List<List<Map<String, String>>> tableDataList = getTableDataList(columnName, types, list);
        List<List<Map<String, String>>> tempTableData = tableDataList.stream()
                .map(a -> a.stream().filter(b -> columnName.contains(b.get("key"))).collect(Collectors.toList()))
                .collect(Collectors.toList());
        return tempTableData;
    }

    //解析查询的列名
    private static List<String> getTableColumnNames(String sql) {
        Pattern compile = Pattern.compile("select\\s+(.*)\\s+from");
        Matcher matcher = compile.matcher(sql);
        ArrayList<String> colName = new ArrayList<>();
        if (matcher.find()) {
            String group = matcher.group(1);
            List<String> collect = Arrays.stream(group.split(",")).map(String::trim).collect(Collectors.toList());
            colName.addAll(new ArrayList<>(collect));
        }
        return colName;
    }

    private static Map<String, String> getWhereClause (String sql){
        HashMap<String, String> map = new HashMap<>();
        Pattern p = Pattern.compile("where\\s+(.*);$", Pattern.CASE_INSENSITIVE);
        Matcher matcher = p.matcher(sql);
        if (matcher.find()) {
            String group = matcher.group(1);
            if(group.contains("and")){
                String[] strings = group.trim().split("and");
                for (String string : strings) {
                    String[] split = string.split("=");
                    String value = split[1].trim();
                    Pattern compile = Pattern.compile("^(\'|\")(.*)(\'|\")$");
                    Matcher matcher1 = compile.matcher(value);
                    if (matcher1.find()) {
                        value = matcher1.group(2);
                    }
                    map.put(split[0].trim(), value);
                }
            } else if (group.contains("AND")) {
                String[] strings = group.trim().split("AND");
                for (String string : strings) {
                    String[] split = string.split("=");
                    String value = split[1].trim();
                    Pattern compile = Pattern.compile("^(\'|\")(.*)(\'|\")$");
                    Matcher matcher1 = compile.matcher(value);
                    if (matcher1.find()) {
                        value = matcher1.group(2);
                    }
                    map.put(split[0].trim(), value);
                }
            } else if (group.contains("OR") || group.contains("or")){
                System.out.println("ERROR: select语句还未支持该类型查询");
            }
            else {
                String[] split = group.trim().split("=");
                String value = split[1].trim();
                Pattern compile = Pattern.compile("^(\'|\")(.*)(\'|\")$");
                Matcher matcher1 = compile.matcher(value);
                if (matcher1.find()) {
                    value = matcher1.group(2);
                }
                map.put(split[0].trim(), value);
            }
        }
        return map;
    }

    private static String getSelectViewSql(String path){
        try {
            File file = new File(path);
            FileReader reader = new FileReader(file);
            BufferedReader bufferedReader = new BufferedReader(reader);
            String s = "";
            int index = 1;
            while((s = bufferedReader.readLine()) != null){
                return s.replace(";~", ";");
            }
            bufferedReader.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        return null;
    }
}
